using System;
using System.Xml;
using System.IO;
using System.Text;

namespace ELS.Configuration
{
	#region ConfigurationSection
	/// <summary>
	/// Represents a section within configuration settings.
	/// </summary>
	public class ConfigurationSection : ConfigurationObjectBase
	{
		#region variables
		private string _name = null;
		private ConfigurationSectionCollection _sections = null;
		private ConfigurationPropertyCollection _properties = null;
		#endregion variables

		#region constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="ELS.Configuration.ConfigurationSection"/> class.
		/// </summary>
		private ConfigurationSection():this ( null )
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ELS.Configuration.ConfigurationSection"/> class.
		/// </summary>
		/// <param name="name">The name of the property. Cannot be null or empty string("").</param>
		public ConfigurationSection( string name )
		{
			_name = name;
			_sections = new ConfigurationSectionCollection( this );
			_properties = new ConfigurationPropertyCollection( this );
		}
		#endregion constructors
		
		#region static methods
		internal static ConfigurationSection FromXml( string xml )
		{
			ConfigurationSection configSection = new ConfigurationSection();
			configSection.Load( xml );
			return configSection;
		}
		#endregion static methods

		#region public properties
		/// <summary>
		/// Gets the name of the section.
		/// </summary>
		public override string Name
		{
			get { return _name; }
		}

		/// <summary>
		/// Gets or sets a collection of sections for this section.
		/// </summary>
		public ConfigurationSectionCollection Sections
		{
			get { return _sections;  }
			set { _sections = value; }
		}

		/// <summary>
		/// Gets or sets a collection of properties for this element.
		/// </summary>
		public ConfigurationPropertyCollection Properties
		{
			get { return _properties;  }
			set { _properties = value; }
		}
		#endregion public properties

		#region public functions

		/// <summary>
		/// Loads the specified XML data.
		/// </summary>
		/// <param name="xml">String containing the XML data to load.</param>
		private void Load ( string xml )
		{
			if ( xml == null )
				throw new ArgumentNullException ( "xml", "xml source cannot be null" );

			
			XmlDocument doc = new XmlDocument();
			doc.LoadXml( xml );
			XmlNamespaceManager nsmgr = new XmlNamespaceManager( doc.NameTable );
			nsmgr.AddNamespace(Constants.NAMESPACE_PREFIX , Constants.NAMESPACE_URI);

			
			_name = doc.DocumentElement.Attributes["name"].InnerText;

			// add properties
			XmlNodeList nodeList = doc.DocumentElement.SelectNodes("./ns:property", nsmgr);
			foreach(XmlNode node in nodeList)
			{
				ConfigurationValueCollection cvc = new ConfigurationValueCollection();
				XmlNodeList values = node.SelectNodes("./ns:value", nsmgr);
				foreach(XmlNode valueNode in values)
				{
						cvc.Add(valueNode.InnerText.Trim());
				}
				ConfigurationProperty configProperty = new ConfigurationProperty( node.Attributes["name"].InnerText, cvc);
				configProperty.Parent = this;
				this.Properties.Add( configProperty );
			}

			// add subsections
			nodeList = doc.DocumentElement.SelectNodes("./ns:sections/ns:section", nsmgr);
			ConfigurationSection configSection = null;
			foreach(XmlNode node in nodeList)
			{
				configSection = ConfigurationSection.FromXml( node.OuterXml );
				configSection.Parent = this;
				this.Sections.Add( configSection );
			}
		}
		
		/// <summary>
		/// Returns the XML representation of the data stored in the <see cref="ELS.Configuration.ConfigurationSection"/>.
		/// </summary>
		/// <returns>A string that is a representation of the data stored in the <see cref="ELS.Configuration.ConfigurationSection"/>.</returns>
		public string GetXml()
		{
			StringBuilder sb = new StringBuilder();
			XmlTextWriter writer = new XmlTextWriter(new StringWriter(sb));
			writer.WriteStartElement("section");
			writer.WriteAttributeString("name", Name);
			foreach(ConfigurationProperty property in Properties)
			{
				writer.WriteRaw(property.GetXml());
			}
			writer.WriteEndElement();

			foreach( ConfigurationSection section in Sections )
			{
				writer.WriteStartElement("sections");
				writer.WriteRaw(section.GetXml());
				writer.WriteEndElement();
			}
			
			return sb.ToString();
		}
		#endregion public functions
	}
	#endregion ConfigurationSection
}
